var delta = 1e-6;
var tooBig = 100000;
var normalCoordinate = {x:[1,0,0],y:[0,1,0],z:[0,0,1],O:[0,0,0]};

function testSameEdge(e1, e2){
	if(testSamePoint(e1.start, e2.start) && testSamePoint(e1.end, e2.end)){
		return true;
	}
	if(testSamePoint(e1.start, e2.end) && testSamePoint(e1.end, e2.start)){
		return true;
	}
	return false;
}
function testSameValue(v1, v2){
	if(Math.abs(v1-v2) < delta){
		return true;
	}
	return false;
}
function testSamePoint(p1, p2){
	if(testSameValue(p1.x, p2.x) && testSameValue(p1.y, p2.y) &&testSameValue(p1.z, p2.z)){
		return true;
	}
	return false;
}
function testsPatchConnection(p1, p2){
	for(var i = 0; i < p1.data.length/2; i++){
		for(var j = 0; j < p2.data.length/2; j++){
			var e1 = makeEdge(p1, i*2, 2);
			var e2 = makeEdge(p2, j*2, 2);
			if(testSameEdge(e1, e2)){
				var e3 = {};
				var e4 = {};
				e3.start = changeCoordinatePoint3(e1.start, p1.coordinate, normalCoordinate);
				e3.end = changeCoordinatePoint3(e1.end, p1.coordinate, normalCoordinate);
				e4.start = changeCoordinatePoint3(e2.start, p2.coordinate, normalCoordinate);
				e4.end = changeCoordinatePoint3(e2.end, p2.coordinate, normalCoordinate);
				if(!testSameEdge(e3, e4)){
					return false;
				}
			}
		}
	}
	return true;
}
function testModelConnection(model){
	for(var i = 0; i < model.patches.length; i++){
		for(var j = i+1; j < model.patches.length; j++){
			if(!testsPatchConnection(model.patches[i], model.patches[j])){
				return false;
			}
		}
	}
	return true;
}
function sinD(d){
	return Math.sin(d/180*Math.PI);
}
function sinR(r){
	return Math.sin(r);
}
function cosD(d){
	return Math.cos(d/180*Math.PI);
}
function cosR(r){
	return Math.cos(r);
}
function cloneObject(obj) {
    var o;
    if (typeof obj == "object") {
        if (obj === null) {
            o = null;
        } else {
            if (obj instanceof Array) {
                o = [];
                for (var i = 0, len = obj.length; i < len; i++) {
                    o.push(cloneObject(obj[i]));
                }
            } else {
                o = {};
                for (var j in obj) {
                    o[j] = cloneObject(obj[j]);
                }
            }
        }
    } else {
        o = obj;
    }
    return o;
}
function removeFromArray(array, item){
	for(var i = 0; i < array.length;i++){
		if(array[i] === item){
			array.splice(i, 1);
			return true;
		}
	}
	return false;
}
function removePatchFromModel(model, patch){
	return removeFromArray(model.patches, patch);
}
function addPatchIntoModel(model, patch){
	return model.patches.push(patch);
}
function addPlaneIntoModel(model, plane){
	return model.planes.push(plane);
}
function clearModelMarks(model){
	for(var i = 0; i < model.planes.length; i++){
		model.planes[i].turned = "unKnown";
		model.planes[i].debugIndex = i;
	}
	model.foldNormalSide = true;
	//alertModel(model);
}
function  changeFromPlaneToPatch(model, superPlane){
	var retValue = [];
	for(var i = 0; i < superPlane.length; i++){
		retValue.push(searchArray(model.patches, model.planes[superPlane[i]].value[0]));
	}
	return retValue;
}
function alertModel(model){
	var temp = "";
	for(var i = 0; i < model.planes.length; i++){
		if(model.planes[i].type == "plane"){
			temp += model.planes[i].debugIndex.toString()+":"+model.planes[i].value[0].debugIndex.toString()+","+model.planes[i].value[1].debugIndex.toString()+"\r\n";
			//alert(temp);
		}else{
			temp += model.planes[i].debugIndex.toString()+":"+model.planes[i].value[0].data+"\r\n";
			//alert(model.planes[i].debugIndex.toString()+":"+model.planes[i].value[0].data);
		}
	}
	alert(temp);
}
function stringAlertModel(model){
	var temp = "";
	for(var i = 0; i < model.planes.length; i++){
		if(model.planes[i].type == "plane"){
			temp += model.planes[i].debugIndex.toString()+":"+model.planes[i].value[0].debugIndex.toString()+","+model.planes[i].value[1].debugIndex.toString()+"\r\n";
			//alert(temp);
		}else{
			temp += model.planes[i].debugIndex.toString()+":"+model.planes[i].value[0].data+"\r\n";
			//alert(model.planes[i].debugIndex.toString()+":"+model.planes[i].value[0].data);
		}
	}
	return temp;
}
function cloneModel(model){
	var retModel = cloneObject(model);
	for(var i = 0; i < model.planes.length; i++){
		retModel.planes[i] = {};
		retModel.planes[i].angle = model.planes[i].angle;
		retModel.planes[i].debugIndex = model.planes[i].debugIndex;
		retModel.planes[i].turned = cloneObject(model.planes[i].turned);
		retModel.planes[i].type = cloneObject(model.planes[i].type);
		retModel.planes[i].value = [];
	}
	for(var i = 0; i < model.planes.length; i++){
		if(model.planes[i].type == "plane"){
			retModel.planes[i].value.push(retModel.planes[model.planes[i].value[0].debugIndex]);
			retModel.planes[i].value.push(retModel.planes[model.planes[i].value[1].debugIndex]);
		}
		else{
			//retModel.planes[i].type == "patch";
			var index = searchArray(model.patches, model.planes[i].value[0]);
			retModel.planes[i].value.push(retModel.patches[index]);
		}
	}
	return retModel;
}
function searchArray(arr, obj){
	for(var i = 0; i < arr.length; i++){
		if(arr[i] == obj){
			return i;
		}
	}
	return -1;
}
function changeModeltoBak(model){
	model.depth = model.bak.depth;
	model.edges = model.bak.edges;
	model.foldIndex = model.bak.foldIndex;
	model.foldNormalSide = model.bak.foldNormalSide;
	model.fullFoldOffset = model.bak.fullFoldOffset;
	model.height = model.bak.height;
	model.patches = model.bak.patches;
	model.planes = model.bak.planes;
	model.superPlanes = model.bak.superPlanes;
	model.thickness = model.bak.thickness;
	model.width = model.bak.width;
}
function updateTree(model, patches){
	if(patches == true || patches == false){
		return ;
	}
	if(!patches.left.turned){
		var temp = patches.left;
		patches.left = patches.right;
		patches.right = temp;
	}
	for(var i = 0; i < model.patches.length; i++){
		if(model.patches[i] == patches.original){
			model.patches.splice(i, 1, patches.right);
			model.patches.push(patches.left);
		}
	}
	for(var i = 0; i < model.planes.length; i++){
		if(model.planes[i].type == "patch"){
			if(model.planes[i].value[0] == patches.original){
				var planeLeft = {type:"patch", angle:0, value:[patches.left]};
				planeLeft.turned = patches.left.turned;
				var planeRight = {type:"patch", angle:0, value:[patches.right]};
				planeRight.turned = patches.right.turned;
				addPlaneIntoModel(model, planeLeft);
				addPlaneIntoModel(model, planeRight);
				model.planes[i].type = "plane";
				model.planes[i].turned = "unKnown";
				if(planeRight.turned == planeLeft.turned){
					model.planes[i].turned = planeLeft.turned;
				}
				model.planes[i].value.splice(0,1);
				model.planes[i].value.push(planeLeft);
				model.planes[i].value.push(planeRight);
			}
		}
	}
}
function foldSuperPlane(model, superPlane, edge, angle, check){

	//var bak = cloneModel(model);
	//model.bak = bak;
	model.foldNormalSide = check;
		
	for(var i = 0; i < superPlane.length; i++){
		var patch = model.patches[superPlane[i]];
		var patches = foldSinglePatch(model, patch, edge, angle);
		if(patches == true || patches == false){
			continue;
		}else{
			updateTree(model, patches);
		}
	}
	
}
function foldInsidePlane(model, destPlane, edge, check){
	if(destPlane.type != "plane"){
		return false;
	}
	foldSinglePlane(model, destPlane.value[0], edge, 180, check);
	foldSinglePlane(model, destPlane.value[1], edge, -180, check);
}
function foldSinglePlane(model, destPlane, edge, angle, checkExTurn){
	if(model.depth == 0 && model.foldNormalSide){
		var bak = cloneModel(model);
		var index = destPlane.debugIndex;
		model.bak = bak;
		model.foldIndex = index;
	}
	model.depth++;
	if(destPlane.type == "plane"){
		//有两个平面;
		var planeLeft = foldSinglePlane(model, destPlane.value[0], edge, angle, false);
		var planeRight = foldSinglePlane(model, destPlane.value[1], edge, angle, false);
		destPlane.value[0] = planeLeft;
		destPlane.value[1] = planeRight;
		destPlane.turned = "unKnown";
		if(planeLeft.turned == "unKnown" && planeRight.turned == "unKnown"){
			//if(planeLeft.type != "plane" || planeRight.type != "plane"){
			//	alert("鬼知道怎么了");
			//}
			if(!planeLeft.value[0].turned){
				var temp = planeLeft.value[0];
				planeLeft.value[0] = planeLeft.value[1];
				planeLeft.value[1] = temp;
			}
			if(!planeRight.value[0].turned){
				var temp = planeRight.value[0];
				planeRight.value[0] = planeRight.value[1];
				planeRight.value[1] = temp;
			}
			var temp = planeLeft.value[1];
			planeLeft.value[1] = planeRight.value[0];
			planeRight.value[0] = temp;
			planeLeft.turned = true;
			planeRight.turned = false;
		}else if(planeLeft.turned != "unKnown" && planeRight.turned != "unKnown"){
			if(planeLeft.turned == planeRight.turned){
				destPlane.turned = planeLeft.turned;
			}else{
				if(!planeLeft.turned){
					var temp = destPlane.value[0];
					destPlane.value[0] = destPlane.value[1];
					destPlane.value[1] = temp;
				}
			}
		} else {
			if(planeLeft.turned == "unKnown"){
				//if(planeLeft.type != "plane"){
				//	alert("error");
				//}
				if(!planeLeft.value[0].turned){
					var temp = planeLeft.value[0];
					planeLeft.value[0] = planeLeft.value[1];
					planeLeft.value[1] = temp;
				}
				if(planeRight.turned){
					var temp = planeLeft.value[1];
					planeLeft.value[1] = destPlane.value[1];
					destPlane.value[1] = temp;
					planeLeft.turned = true;
				}else{
					var temp = planeLeft.value[0];
					planeLeft.value[0] = destPlane.value[1];
					destPlane.value[1] = temp;
					temp = destPlane.value[0];
					destPlane.value[0] = destPlane.value[1];
					destPlane.value[1] = temp;
					destPlane.value[1].turned = false;
				}
			}else{
				//if(planeRight.type != "plane"){
				//	alert("error");
				//}
				if(!planeRight.value[0].turned){
					var temp = planeRight.value[0];
					planeRight.value[0] = planeRight.value[1];
					planeRight.value[1] = temp;
				}
				if(planeLeft.turned){
					var temp = planeRight.value[1];
					planeRight.value[1] = destPlane.value[0];
					destPlane.value[0] = temp;
					temp = destPlane.value[0];
					destPlane.value[0] = destPlane.value[1];
					destPlane.value[1] = temp;
					destPlane.value[0].turned = true;
				}else{
					var temp = planeRight.value[0];
					planeRight.value[0] = destPlane.value[0];
					destPlane.value[0] = temp;
					planeRight.turned = false;
				}
			}
		}
		destPlane.angle = angle;
	}
	if(destPlane.type == "patch"){
		//只有一个面片;
		var patches = foldSinglePatch(model, destPlane.value[0], edge, angle);
		if(patches == true || patches == false){
			destPlane.turned = patches;
		}else{
			//alert(patches.original);
			removePatchFromModel(model, patches.original);
			addPatchIntoModel(model, patches.left);
			addPatchIntoModel(model, patches.right);
			var planeLeft = {type:"patch", angle:0, value:[patches.left]};
			planeLeft.turned = patches.left.turned;
			var planeRight = {type:"patch", angle:0, value:[patches.right]};
			planeRight.turned = patches.right.turned;
			addPlaneIntoModel(model, planeLeft);
			addPlaneIntoModel(model, planeRight);
			destPlane.type = "plane";
			destPlane.turned = "unKnown";
			if(planeRight.turned == planeLeft.turned){
				destPlane.turned = planeLeft.turned;
			}
			destPlane.value.splice(0,1);
			destPlane.value.push(planeLeft);
			destPlane.value.push(planeRight);
		}
	}
	model.depth--;
	if(model.depth == 0){
		if(model.foldNormalSide){
			var connect = testModelConnection(model);
			if(!connect){
				var index = model.foldIndex;
				changeModeltoBak(model);
				model = model.bak;
				model.foldNormalSide = false;
				return foldSinglePlane(model, model.planes[index], edge, angle, false);
			}
		}
		clearModelMarks(model);
	}
	return destPlane;
}
function makeEdge(patch, offset, step){
	var retEdge = {};
	retEdge.start = {x:patch.data[offset], y:patch.data[offset+1],z:0};
	if(patch.data.length == offset+2){
		retEdge.end = {x:patch.data[0], y:patch.data[1],z:0};
	} else {
		retEdge.end = {x:patch.data[offset+step], y:patch.data[offset+step+1],z:0};
	}
	return retEdge;
}
function testPointInsideLine(edge, point){
	var retValue = {};
	if(delta < (edge.end.x- edge.start.x) ){
		if(point.x >= edge.start.x && point.x < edge.end.x){
			retValue.on = true;
		}else{
			retValue.on = false;
		}
	}else if((edge.start.x - edge.end.x ) > delta){
		if(point.x <= edge.start.x && point.x > edge.end.x){
			retValue.on = true;
		}else{
			retValue.on = false;
		}
	}else {
		if(edge.start.y <= edge.end.y){
			if(point.y >= edge.start.y && point.y < edge.end.y){
				retValue.on = true;
			}else{
				retValue.on = false;
			}
		}else if(edge.start.y > edge.end.y){
			if(point.y <= edge.start.y && point.y > edge.end.y){
				retValue.on = true;
			}else{
				retValue.on = false;
			}
		}
	}
	if(retValue.on){
		if(delta > Math.sqrt((point.x - edge.start.x)*(point.x - edge.start.x) + (point.y - edge.start.y)*(point.y - edge.start.y))){
			retValue.vertex = true;
		}else{
			retValue.vertex = false;
		}
	}
	return retValue;
}
function addLinePatchCross(edge, i, point, cross1, cross2){
	var info = testPointInsideLine(edge, point);
	if(!info.on){
		return false;
	}
	if(cross1.type == null){
		if(info.vertex){
			cross1.type = "vertex";
		}else{
			cross1.type = "edge";
		}
		cross1.index = i;
		cross1.point = cloneObject(point);
		return false;
	}else{
		if(info.vertex){
			cross2.type = "vertex";
		}else{
			cross2.type = "edge";
		}
		cross2.index = i;
		cross2.point = cloneObject(point);
		return true;
	}
}
function turnUnconnectedPatch(model, patch, edge, localEdge, angle){
	//return;
	var l = changeLineFormat(edge);
	if(model.foldNormalSide == (testLinePatchSide(l, patch, patch.coordinate) > 0)){
	//var pt = changeCoordinatePoint3({x:patch.data[4], y:patch.data[5], z:0}, patch.coordinate, normalCoordinate);
	//if(l.A*pt.x + l.B*pt.y + l.C > 0){
		//donothing();
		return false;
	}else{
		rotateCoordinate(patch.coordinate, edge, angle, patch.coordinate);
		return true;
	}
}
function splitPatch(model, patch, cross1, cross2, edge, localEdge, angle){
	var length = patch.data.length/2;
	var retValue = {};
	retValue.original = patch;
	retValue.left = {coordinate:{},data:[]};
	//retValue.right = [];
	retValue.left.data.push(cross1.point.x,cross1.point.y,cross2.point.x,cross2.point.y);
	retValue.right = cloneObject(retValue.left);
	for(var i = cross2.index; ; i = (i-1+length)%length){
		if(i == cross2.index && cross2.type == "vertex"){
			continue;
		}
		retValue.right.data.push(patch.data[i*2], patch.data[i*2+1]);
		if(i == (cross1.index+1)%length){
			break;
		}
	}
	for(var i = (cross2.index+1)%length; ; i = (i+1)%length){
		if(i == cross1.index){
			if(cross1.type == "edge"){
				retValue.left.data.push(patch.data[i*2], patch.data[i*2+1]);
			}
			break;
		}
		retValue.left.data.push(patch.data[i*2], patch.data[i*2+1]);
	}
	var sizeA = getShapeSize(retValue.left.data);
	var sizeB = getShapeSize(retValue.right.data);
	if(sizeA > sizeB){
		if(sizeA > sizeB*tooBig){
			return turnUnconnectedPatch(model, patch, edge, localEdge, angle);
		}
	}else{
		if(sizeB > sizeA*tooBig){
			return turnUnconnectedPatch(model, patch, edge, localEdge, angle);
		}
	}
	var l = changeLineFormat(edge);
	var pt = changeCoordinatePoint3({x:retValue.left.data[4], y:retValue.left.data[5], z:0}, patch.coordinate, normalCoordinate);
	if(model.foldNormalSide == (testLinePatchSide(l,retValue.left, patch.coordinate) > 0)){
	//if(l.A*pt.x + l.B*pt.y + l.C > 0){
		retValue.left.coordinate = cloneObject(patch.coordinate);
		retValue.right.coordinate = {};
		rotateCoordinate(retValue.right.coordinate, edge, angle, patch.coordinate);
		retValue.right.turned = true;
		retValue.left.turned = false;
		var temp = retValue.left;
		retValue.left = retValue.right;
		retValue.right = temp;
	}else{
		retValue.right.coordinate = cloneObject(patch.coordinate);
		retValue.left.coordinate = {};
		rotateCoordinate(retValue.left.coordinate, edge, angle, patch.coordinate);
		retValue.right.turned = false;
		retValue.left.turned = true;
	}
	retValue.right.color = cloneObject(retValue.original.color);
	retValue.left.color = cloneObject(model.colorList[model.colorPointer]);
	model.colorPointer = (model.colorPointer+1)%(model.colorList.length);
	return retValue;
}
function testLinePatchSide(line, patch, coordinate){
	var retValue = 0;
	var vCount = patch.data.length/2;
	for(var i = 0; i < vCount; i++){
		var pt = changeCoordinatePoint3({x:patch.data[i*2], y:patch.data[i*2+1], z:0}, coordinate, normalCoordinate);
		if(line.A*pt.x + line.B*pt.y + line.C > delta){
			if(retValue == -1){
				return 0;
			}
			retValue = 1;
		}
		if(line.A*pt.x + line.B*pt.y + line.C < -1*delta){
			if(retValue == 1){
				return 0;
			}
			retValue = -1;
		}
	}
	return retValue;
}
function getShapeSize(shape){
	var retSize = 0;
	var vCount = shape.length/2;
	if(vCount <= 2){
		return 0;
	}
	for(var i = 1; i < vCount-1; i++){
		retSize+=Math.abs(crossMulVector3([shape[i*2]-shape[0],shape[i*2+1]-shape[1],0],[shape[i*2+2]-shape[0],shape[i*2+2+1]-shape[1],0])[2])/2;
	}
	return retSize;
}
function rotateCoordinate(destC, edge, angle, oriC){
	destC.x = rotateVector(makeVector(edge.start, edge.end), angle, oriC.x);
	destC.y = rotateVector(makeVector(edge.start, edge.end), angle, oriC.y);
	destC.z = rotateVector(makeVector(edge.start, edge.end), angle, oriC.z);
	destC.O = rotateVector(makeVector(edge.start, edge.end), angle, [oriC.O[0]-edge.start.x, oriC.O[1]-edge.start.y, oriC.O[2]-edge.start.z]);
	destC.O[0]+=edge.start.x;
	destC.O[1]+=edge.start.y;
	destC.O[2]+=edge.start.z;
}
function testCrossAdjoin(patch, cross1, cross2){
	var length = patch.data.length/2;
	if(cross2.index == (cross1.index+1)%length){
		return true;
	}else{
		return false;
	}
}
function testCrossInPatch(patch, cross1, cross2){
	if(cross1.type == null || cross2.type == null){
		return false;
	}
	if(cross1.type == "vertex" && cross2.type == "vertex"){
		if(testCrossAdjoin(patch, cross1, cross2)){
			return false;
		}
	}
	return true;
}
function foldSinglePatch(model, patch, edge, angle){
	var localEdge = {start:changeCoordinatePoint3(edge.start,normalCoordinate, patch.coordinate), end:changeCoordinatePoint3(edge.end, normalCoordinate, patch.coordinate)};
	if(Math.abs(localEdge.start.z) > delta || Math.abs(localEdge.end.z) > delta){
		//alert("误差太大了\nstart:"+localEdge.start.z+"\nend:"+localEdge.end.z);
		return turnUnconnectedPatch(model, patch, edge, localEdge, angle);
	}
	if(patch.data.length == 0 || patch.data.length % 2 != 0){
		return null;
	}
	var edgeCount = patch.data.length / 2;
	var cross1 = {type:null,index:null,point:null};
	var cross2 = cloneObject(cross1);
	for(var i = 0; i < edgeCount; i++){
		var testEdge = makeEdge(patch, i*2, 2);
		var crossPoint = calcLineLineCross(localEdge,testEdge);
		if(crossPoint == null){
			continue;
		}
		if(addLinePatchCross(testEdge, i, crossPoint, cross1, cross2)){
			break;
		}
	}
	if(testCrossInPatch(patch, cross1, cross2)){
		return splitPatch(model, patch, cross1, cross2, edge, localEdge, angle);
	}else{
		return turnUnconnectedPatch(model, patch, edge, localEdge, angle);
	}
}
function testPoint(point1, point2){
	if(Math.abs(point1.x - point2.x) < delta && Math.abs(point1.y - point2.y) < delta){
		return true;
	} else {
		return false;
	}
}
function testLineLineSharePoint(line1, line2, retPoint){
	if(testPoint(line2.start, line1.start) || testPoint(line2.start, line1.end)){
		retPoint.x = line2.start.x;
		retPoint.y = line2.start.y;
		return true;
	}else if(testPoint(line2.end, line1.start) || testPoint(line2.end, line1.end)){
		retPoint.x = line2.end.x;
		retPoint.y = line2.end.y;
		return true;
	}else {
		return false;
	}
}
//line1 line2表示形式为两个点，被视为无限长的直线。line1 是折线，line2是边。
function calcLineLineCross(line1, line2){
	var retPoint = {x:0,y:0,z:0};
	if(testLineLineSharePoint(line1, line2, retPoint)){
		return retPoint;
	}
	var l1 = changeLineFormat(line1);
	var l2 = changeLineFormat(line2);
	if(l1.A*l2.B == l1.B *l2.A){
		retPoint = null;
	}else{
		retPoint.x = (l1.B*l2.C - l1.C *l2.B)/(l1.A*l2.B - l1.B *l2.A);
		retPoint.y = (l1.A*l2.C - l1.C *l2.A)/(l1.B *l2.A - l1.A*l2.B);
	}
	return retPoint;
}
function changeLineFormat(line){
	var retLine = {A:0,B:0,C:0};
	if(line.start.x == line.end.x){
		retLine.A = 1;
		retLine.B = 0;
		retLine.C = -1*line.start.x;
	} else if(line.start.y == line.end.y){
		retLine.A = 0;
		retLine.B = 1;
		retLine.C = -1*line.start.y;
	} else {
		retLine.A = (line.end.y - line.start.y)/(line.start.x - line.end.x);
		retLine.B = 1;
		retLine.C = -1*(retLine.A*line.start.x+ line.start.y);
	}
	return retLine;
}
function foldPaperTest(model, planeNum, edge, angle){
	if(angle != 180 && angle != -180){
		return model;
	}
	var retModel = cloneObject(model);
	var dstPlane = model.planes[planeNum];
}
function createEmptyPaper(width, height, thickness){
	var retModel = {};
	
	retModel.width = width;
	retModel.height = height;
	retModel.thickness = thickness;
	retModel.fullFoldOffset = retModel.thickness*Math.PI*0.25;
	retModel.patches = [];
	retModel.planes = [];
	retModel.superPlanes = [];
	retModel.edges = [];
	
	var firstPatch = {coordinate: cloneObject(normalCoordinate),data:[0, 0, width, 0, width, height, 0, height]};
	retModel.patches.push(firstPatch);
	
	var firstPlane = {type:"patch", angle:0, value:[firstPatch]};
	//firstPlane = {type:"plane", angle:0, value:[somePlane]};
	retModel.planes.push(firstPlane);
	
	//var firstEdge = {};
	//firstEdge.left = 0;
	//firstEdge.right = -1;
	//firstEdge.edge = {};
	//firstEdge.edge.start = {x:0,y:0,z:0};
	//firstEdge.edge.end = {x:width, y:height, z:0};
	//retModel.edges.push(firstEdge);
	//retModel.rootEdge = 0;
	retModel.depth = 0;
	retModel.foldNormalSide = true;
	retModel.foldIndex = 0;
	retModel.colorList = [];
	for(var i = 0; i < 256; i++){
		retModel.colorList.push([Math.random(), Math.random(), Math.random(), 1.0]);
	}
	retModel.colorPointer = 1;
	retModel.patches[0].color = cloneObject(retModel.colorList[0]);
	return retModel;
}
function makeVector(p1, p2){
	return [p2.x-p1.x, p2.y-p1.y, p2.z-p1.z];
}
function pluVector3(v1, v2){
	return [v1[0]+v2[0], v1[1]+v2[1], v1[2]+v2[2]];
}
function numMulVector3(n, v){
	return [n*v[0],n*v[1], n*v[2]];
}
function subVector3(v1, v2){
	return [v1[0]-v2[0], v1[1]-v2[1], v1[2]-v2[2]];
}
function dotMulVector3(v1, v2){
	return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
}
function crossMulVector3(v1, v2){
	return [v1[1]*v2[2]-v2[1]*v1[2], v1[2]*v2[0]-v2[2]*v1[0], v1[0]*v2[1]-v2[0]*v1[1]];
}
function vectorLength3(v){
	return Math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
}
function NormalizeVector3(v){
	var length = vectorLength3(v);
	if(length == 0){
		return cloneObject(v);
	}else{
		return [v[0]/length, v[1]/length, v[2]/length];
	}
}
function rotateVector(axle, angle, vector){
	var normalAxle = NormalizeVector3(axle);
	var vectorLength = vectorLength3(vector);
	var vectorHorLength = dotMulVector3(normalAxle, vector);
	var vectorHor = numMulVector3(vectorHorLength, normalAxle);
	var vectorPer = subVector3(vector, vectorHor);
	var vectorPerHor = NormalizeVector3(vectorPer);
	var vectorPerPer = NormalizeVector3(crossMulVector3(axle, vectorPerHor));
	var vectorPerNorTurned = pluVector3(numMulVector3(cosD(angle), vectorPerHor), numMulVector3(sinD(angle), vectorPerPer));
	return pluVector3(vectorHor, numMulVector3(vectorLength3(vectorPer), vectorPerNorTurned));
}
function changeCoordinatePoint3(p, c1, c2){
	var temp = pluVector3(numMulVector3(p.x, c1.x), numMulVector3(p.y, c1.y));
	temp = pluVector3(temp, numMulVector3(p.z, c1.z));
	temp = pluVector3(temp, c1.O);
	var pInNormal = subVector3(temp, c2.O);
	var retPoint = {x:0, y:0,z:0};
	retPoint.x = dotMulVector3(pInNormal, c2.x);
	retPoint.y = dotMulVector3(pInNormal, c2.y);
	retPoint.z = dotMulVector3(pInNormal, c2.z);
	return retPoint;
}
